<!--
Date: 2025-08-13
Copyright (c) 2025 CAX Conversion Project
-->
<template>
  <div class="mapping-relation">
    <div class="tips">
      注：该文件存在 N 个sheet页，请根据实际情况选择sheet页，并从库类型中选择其下对应表单建立映射关系。系统默认展示第一个sheet页的相关信息以更好的帮助您建立映射关系。
如果其他sheet页也需要建立映射关系，则点击<el-button type="primary" link style="font-size: 12px"
>继续添加映射关系</el-button>按钮。
    </div>
    <div class="mapping_table">
      <div class="mapping-header">
        <div class="resource-link"><label for="">源文件：</label><span class="tips_color">{{ props.uploadFile && props.uploadFile.name }}</span></div>
        <div class="storage-name"><label for="">要素库类型：</label><span class="tips_color">{{ props.formInfo.databaseName }}</span></div>
      </div>
      <el-card v-for="(card, cIndex) in mappingList" class="box-card" :key="'card' + cIndex">
        <template #header>
          <div class="card-header">
            <span class="mapping-name">映射关系{{cIndex + 1}} </span>
            <el-icon v-if="mappingList.length > 1" :size="20" @click="deleteCard(cIndex)">
              <CloseBold />
            </el-icon>
          </div>
        </template>
        <div class="mapping-item-card">
          <div class="btns">
            <!-- <el-button type="primary" size="small" :icon="Delete">去除对应</el-button>
            <el-button type="primary" size="small" :icon="RefreshLeft">重置对应</el-button> -->
            <div class="btn delete" @click="delMapping(cIndex)">
              <el-icon :size="16">
                <Delete />
              </el-icon> 去除对应
            </div>
            <div class="btn reset" @click="resetMapping(cIndex)">
              <el-icon :size="16">
                <RefreshLeft />
              </el-icon> 重置对应
            </div>
          </div>
          <div class="card-main">
            <div class="left table-item">
              <label class="des" for="">上传Excel文件Sheet页选择：</label>
              <el-select size="small" v-model="card.sheetName" @change="changeSheet($event, cIndex)">
                <el-option v-for="sheet in card.sheetList" :key="sheet" :label="sheet" :value="sheet"></el-option>
              </el-select>
              <div class="table">
                <table style="width: 100%" border="1" cellspacing="1">
                  <thead>
                    <tr>
                      <th>序号</th>
                      <th>字段名称</th>
                    </tr>
                  </thead>
                  <tbody>
                    <template v-for="(item,index) in card.fromFieldList">
                      <tr v-if="!(hasMappingFields.length > 0 && hasMappingFields[cIndex].indexOf(item) > -1)" :class="hasMappingFields.length > 0 && hasMappingFields[cIndex].indexOf(item) > -1 ? 'has-mapping' : ''"  :key="index">
                        <td>{{ index + 1 }}</td>
                        <td
                          draggable="true" 
                          @dragstart="dragStart('file', item, cIndex, index)" 
                          @dragover="allowDrop" 
                          @dropend="drop($event, cIndex,  index)"
                        >{{ item }}</td>
                      </tr>
                    </template>
                  </tbody>
                </table>
              </div>
            </div>
            <div class="right table-item">
              <label class="des" for="">要素库类型下的表名称：</label>
              <el-select size="small" v-model="card.tableName" @change="changeTable($event, cIndex)">
                <el-option v-for="table in card.tableList" :key="table" :label="table" :value="table"></el-option>
              </el-select>
              <div class="table">
                <table style="width: 100%" border="1" cellspacing="1">
                  <thead>
                    <tr>
                      <th>源字段</th>
                      <th><=></th>
                      <th>目标字段</th>
                      <th>字段类型</th>
                      <th>字段长度</th>
                    </tr>
                  </thead>
                  <tbody>
                    <tr :class="item.isClick ? 'has-click' : ''" v-for="(item,index) in card.toFieldList" :key="index" @click="tableItemClick(cIndex, index)">
                      <td
                        draggable="true"
                        @dragstart="dragStart('end', item, cIndex, index)" 
                        @dragover="allowDrop"
                        @drop="itemDrap($event, cIndex, index)"
                      >{{ item.metadataField }}</td>
                      <td>{{ index + 1 }}</td>
                      <td><span v-if="item.needFlag == '1'" style="color:red;font-size:14px;padding-right:3px;">*</span>{{ item.targetField }}</td>
                      <td>{{ item.targetFieldType }}</td>
                      <td>{{ item.targetFieldLength }}</td>
                    </tr>
                  </tbody>
                </table>
              </div>
            </div>
          </div>
        </div>
      </el-card>
      <div class="tips">
        注：选中左侧Sheet表中的「字段名称」所在的行，直接拖动到右侧「源字段」所在列的行，即可建立映射关系。
      </div>
      <div class="option_btn">
        <el-button type="primary" @click="addMapping()">继续添加映射关系</el-button>
      </div>
    </div>
  </div>
</template>
<script setup>
import { CirclePlus, Delete, RefreshLeft, CloseBold } from '@element-plus/icons-vue';
import { getMetadataTableInfo } from '@/api/metaData';
const props = defineProps(['tableHeaderMap', 'sheetsDataMap', 'isBack', 'mappingData', 'uploadFile', 'formInfo', 'isSearchTableInfo']);
// const emit = defineEmits(['handleEvent']);
const checkedTreeData = ref(props?.checkedTreeData);
const showAllField = ref(false);
const targetFromIndex = ref([0, 0]); 
const targetEndIndex = ref([0, 0]); 
const targetFromItem = ref({});
const targetEndItem = ref({});
const dropType = ref('');
const curClickedSheet = ref(0);
const hasMappingFields = ref([]);
const mappingList = ref([]); // 整个映射集合
const sheetAll = ref([]); // 上传文件sheet集合
const tableAll = ref([]); // 要素库类型下的表集合
const fromFieldList = ref([])
const toFieldTableList = ref([])

// 点击选中table字段
const tableItemClick = (cIndex, index) => {
  mappingList.value[cIndex].toFieldList[index].isClick = !mappingList.value[cIndex].toFieldList[index].isClick;
}

// 新增映射 
const addMapping = () => {
  if (mappingList.value.length == sheetAll.value.length) {
    // 校验当前sheet页是否已全部匹配 全部匹配不能新增映射
    ElMessage({ showClose: true, message: '暂无sheet页选择！', type: 'warning' });
    return;
  }
  let hasChooseSheets = mappingList.value.map(item => item.sheetName);
  let sheetList = sheetAll.value.filter(item => !hasChooseSheets.includes(item));
  let hasChooseTables = mappingList.value.map(item => item.tableName);
  let tableList = tableAll.value.filter(item => !hasChooseTables.includes(item));
  mappingList.value.push({
    sheetName: '',
    sheetList,
    tableName: '',
    tableList,
    toFieldList: [],
    fromFieldList: []
  })
}
// 去除对应
const delMapping = (cIndex) => {
  mappingList.value[cIndex].toFieldList.forEach(item => {
    if (item.isClick) {
      item.metadataField = '';
      item.isClick = false;
    }
  })
}
// 重置对应 -- 清空所有对应关系
const resetMapping = (cIndex) => {
  mappingList.value[cIndex].toFieldList.forEach(field => {
    field.metadataField = '';
    field.isClick = false;
  })
}
// 重置各个映射下的sheet枚举项
const resetSheetList = () => {
  let hasChooseSheets = mappingList.value.map(item => item.sheetName);
  mappingList.value.forEach(item => {
    let sheetList = sheetAll.value.filter(item => !hasChooseSheets.includes(item));
    item.sheetList = [...sheetList, item.sheetName];
  })
}
// 重置各个映射下的table枚举项
const resetTableList = () => {
  let hasChooseTables = mappingList.value.map(item => item.tableName);
  mappingList.value.forEach(item => {
    let tableList = tableAll.value.filter(item => !hasChooseTables.includes(item));
    item.tableList = [...tableList, item.tableName];
  })
}
// 切换sheet页 -- 实时同步其他sheet页选择项
const changeSheet = (val, index) => {
  mappingList.value[index].fromFieldList = props.tableHeaderMap[val];
  mappingList.value[index].toFieldList.forEach(item => item.metadataField = '')
  resetSheetList();
}
// 切换table
const changeTable = (val, index) => {
  let toFieldList = toFieldTableList.value.find(item => item.tableName == val)?.mapFiledsList || []
  toFieldList.forEach(item => item.metadataField = '');
  mappingList.value[index].toFieldList = toFieldList;
  resetTableList();
}
// 删除映射关系
const deleteCard = (index) => {
  mappingList.value.splice(index, 1);
  resetSheetList();
  resetTableList();
}
// 切换table sheet 
const checkTableSheet = (index) => {
  curClickedSheet.value = index
}
// 点击事件
const dragStart = (type, item, cIndex, index) => {
  // event.dataTransfer.setData('text/plain', event.target.innerText);
  if (hasMappingFields.value[cIndex].includes(item)) {
    targetEndIndex.value = [-1, -1];
    targetEndItem.value = null;
    targetFromIndex.value = [-1, -1];
    targetFromItem.value = null;
    return;
  }
  if (type == 'end') {
    dropType.value = 'CHANGE';
    targetEndIndex.value = [cIndex, index];
    targetEndItem.value = item;
  } else {
    dropType.value = 'ADD';
    targetFromIndex.value = [cIndex, index];
    targetFromItem.value = item;
  }
}
// 判断已经映射过的字段
const checkIsMappingField = () => {

}
const allowDrop = (e) => {
  e.preventDefault()
}
const drop = (event, index) =>  {
  console.log(event, index)
}
const dragover = (event) => {

}
const dragenter = (event) => {
  console.log('event', event)
}
const itemDrap = (event, cIndex, index) => {
  if (!targetEndItem.value && dropType.value == 'ADD') {
    return;
  }
  if (dropType.value == 'ADD') {
    mappingList.value[cIndex].toFieldList[index].metadataField = targetFromItem.value;
  } else {
    mappingList.value[cIndex].toFieldList[index].metadataField = targetEndItem.value.metadataField;
    targetEndIndex.value[1] !== index && (mappingList.value[targetEndIndex.value[0]].toFieldList[targetEndIndex.value[1]].metadataField = '')
  }
}

const dragItemEnter = (ele, index) => {
  // this.$emit("on-end", ele, index)
  console.log('dragItemEnter', ele, index)
}
watch(
  props.checkedTreeData,
  (newVal) => {
    checkedTreeData.value = newVal;
  },
  { deep: true, immediate: true }
);
watch(
  mappingList.value,
  (newVal) => {
    hasMappingFields.value = [];
    newVal.length > 0 && newVal.forEach(mapping => {
      hasMappingFields.value.push(mapping.toFieldList.filter(item => item.metadataField !== '').map(item => item.metadataField));
    })
  },
  { deep: true, immediate: true }
);
watch(
  props.mappingData,
  (newVal) => {
    hasMappingFields.value = [];
    newVal.length > 0 && newVal.forEach(mapping => {
      hasMappingFields.value.push(mapping.toFieldList.filter(item => item.metadataField !== '').map(item => item.metadataField));
    })
  },
  { deep: true, immediate: true }
);
// 数据初始化
const initData = () => {
  sheetAll.value = Object.keys(props.tableHeaderMap);
  toFieldTableList.value.forEach(item => {
    item.mapFiledsList.forEach(field => field.isClick = false)
  })
  tableAll.value = toFieldTableList.value.map(item => item.tableName)
  console.log(props.isSearchTableInfo)
  if (props.mappingData && props.mappingData.length > 0 && !props.isSearchTableInfo) {
    mappingList.value = props.mappingData;
  } else {
    mappingList.value.push({
      sheetName: sheetAll.value[0],
      sheetList: sheetAll.value,
      tableName: tableAll.value[0],
      tableList: tableAll.value,
      fromFieldList: props.tableHeaderMap[sheetAll.value[0]],
      toFieldList: toFieldTableList.value[0].mapFiledsList
    }); 
  }
}
// 获取要素库表信息
const getTableInfo = async () => {
  const { businessId, databaseId } = props.formInfo;
  await getMetadataTableInfo({businessId, databaseId }).then(res => {
    toFieldTableList.value = res.data;
  })
}
onMounted(async () => {
  // 切换要素库类型和业务场景  重新查询表结构信息
  await getTableInfo();
  initData();
});
defineExpose({
  mappingList
});
</script>
<style lang="scss" scoped>
@import "../index.scss";
.mapping-relation {
  padding: 20px;
  width: 100%;
  .tips_color {
    color: #409eff;
  }
  .mapping_table {
    // display: flex;
    margin-top: 10px;
    // border: 1px solid #dddddd7a;
    padding: 0 10px;
    .mapping-header {
      display: flex;
      height: 30px;
      line-height: 30px;
      .resource-link {
        flex: 0 0 40%;
        margin-right: 50px;
      }
      .storage-name {
        flex: 1;
      }
    }
    .box-card {
      margin-top: 10px;
      .card-header {
        display: flex;
        align-items: center;
        justify-content: space-between;
        .mapping-name {
          font-size: 14px;
          font-weight: 600;
        }
      }
      .mapping-item-card {
        .btns {
          display: flex;
          align-items: center;
          margin-left: 40%;
          .delete {
            margin-right: 10px;
          }
          .btn {
            display: flex;
            align-items: center;
            cursor: pointer;
          }
        }
        .card-main{
          display: flex;
          margin-top: 10px;
          .left {
            flex: 0 0 40%;
            margin-right: 50px;
          }
          .right {
            flex: 1;
          }
          .table-item {
            .des {
              height: 24px;
              line-height: 24px;
              font-weight: 500;
            }
          }
          .table {
            margin-top: 10px;
            width: 100%;
          }
        } 
      }
    }
    .option_btn {
      margin-top: 10px;
    }
  }
}

</style>